home *** CD-ROM | disk | FTP | other *** search
Text File | 1999-06-25 | 20.2 KB | 851 lines | [TEXT/CWIE] |
- // ===========================================================================
- // COffscreenBehavior.cp ©1999 Eric Traut
- // ===========================================================================
-
- #include "COffscreenBehavior.h"
- #include "CShadowWindow.h"
- #include "COutOfContextApp.h"
-
- #define UPDATE_WHEN_TRACKING 0
-
-
- Boolean COffscreenBehavior::sOverrideQDProcsInited = false;
- CQDProcs COffscreenBehavior::sOverrideQDProcs;
-
- // ---------------------------------------------------------------------------
- // • COffscreenBehavior
- // ---------------------------------------------------------------------------
-
- COffscreenBehavior::COffscreenBehavior(
- CShadowWindow & inShadowWindow,
- Boolean inAllocateBacking,
- Boolean inDrawEveryTick)
- : CWindowBehavior(inShadowWindow)
- {
- mBackingGWorld = NULL;
- mRenderingGWorld = NULL;
- mBackingChanged = false;
- mGWorldsAllocated = false;
- mAllocateBacking = inAllocateBacking;
- mDrawEveryTick = inDrawEveryTick;
- mLastBlitTicks = ::TickCount();
-
- if (!sOverrideQDProcsInited)
- InitOverrideQDProcs();
-
- CWindowRecord * colorWindow = inShadowWindow.GetMacWindow();
- mOrigQDProcs = colorWindow->port.grafProcs;
- mQDProcsOverridden = true;
-
- colorWindow->port.grafProcs = &sOverrideQDProcs;
-
- CWindowRecord * macWindow = mShadowWindow.GetMacWindow();
- Rect entirePort = {-0x4000, -0x4000, 0x4000, 0x4000};
-
- ::SetPort(reinterpret_cast<GrafPtr>(macWindow));
-
- ::InvalRect(&entirePort);
-
- mFinderOffscreen = NULL;
- }
-
-
- // ---------------------------------------------------------------------------
- // • ~COffscreenBehavior
- // ---------------------------------------------------------------------------
-
- COffscreenBehavior::~COffscreenBehavior(void)
- {
- DeleteGWorlds();
- }
-
-
- // ---------------------------------------------------------------------------
- // • DeleteGWorlds
- // ---------------------------------------------------------------------------
-
- void
- COffscreenBehavior::DeleteGWorlds(void)
- {
- if (mRenderingGWorld != NULL)
- {
- ::DisposeGWorld(mRenderingGWorld);
- mRenderingGWorld = NULL;
- }
-
- if (mBackingGWorld != NULL)
- {
- ::DisposeGWorld(mBackingGWorld);
- mBackingGWorld = NULL;
- }
-
- mGWorldsAllocated = false;
- }
-
-
- // ---------------------------------------------------------------------------
- // • SyncWithShadowWindow
- // ---------------------------------------------------------------------------
-
- Boolean
- COffscreenBehavior::SyncWithShadowWindow(void)
- {
- Boolean neededChanged = false;
-
- if (!mGWorldsAllocated || GWorldNeedsSynching())
- {
- // In case one was allocated, delete them both
- DeleteGWorlds();
-
- AllocateNewGWorlds();
- neededChanged = true;
- }
-
- return !neededChanged;
- }
-
-
- // ---------------------------------------------------------------------------
- // • ShouldBlitAtIdleTime
- // ---------------------------------------------------------------------------
-
- Boolean
- COffscreenBehavior::ShouldBlitAtIdleTime(void)
- {
- if (!mGWorldsAllocated)
- return false;
-
- if (DidOffscreenChange())
- return true;
-
- if (mDrawEveryTick)
- {
- UInt32 curTickCount = ::TickCount();
-
- if (curTickCount != mLastBlitTicks)
- {
- mLastBlitTicks = curTickCount;
- return true;
- }
- }
-
- return false;
- }
-
-
- // ---------------------------------------------------------------------------
- // • DoIdleTask
- // ---------------------------------------------------------------------------
-
- void
- COffscreenBehavior::DoIdleTask(
- Boolean inGNETime)
- {
- #pragma unused (inGNETime)
-
- if (ShouldBlitAtIdleTime())
- {
- if (mAllocateBacking)
- {
- StGWorldLocker backingLocker(mBackingGWorld, false);
- StGWorldLocker renderingLocker(mRenderingGWorld);
-
- if (RenderToGWorld(backingLocker, renderingLocker))
- CopyGWorldToScreen(renderingLocker);
- }
- else
- {
- StGWorldLocker renderingLocker(mRenderingGWorld);
- if (RenderToGWorld(renderingLocker))
- CopyGWorldToScreen(renderingLocker);
- }
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • AllocateNewGWorlds
- // ---------------------------------------------------------------------------
-
- void
- COffscreenBehavior::AllocateNewGWorlds(void)
- {
- try
- {
- CWindowRecord * colorWindow;
- QDErr err;
-
- Assert_(COutOfContextApp::GetAppHeap() == ::GetZone());
-
- // Allocate two new 16-bit GWorlds
- colorWindow = mShadowWindow.GetMacWindow();
- mGWorldRect = colorWindow->port.portRect;
- ::OffsetRect(&mGWorldRect, -mGWorldRect.left, -mGWorldRect.top);
-
- if (mAllocateBacking)
- {
- err = ::NewGWorld( &mBackingGWorld,
- 16,
- &mGWorldRect,
- NULL,
- NULL,
- 0);
- ThrowIfOSErr_(err);
- ThrowIfNULL_(mBackingGWorld);
- }
-
- err = ::NewGWorld( &mRenderingGWorld,
- 16,
- &mGWorldRect,
- NULL,
- NULL,
- 0);
- ThrowIfOSErr_(err);
- ThrowIfNULL_(mRenderingGWorld);
-
- mGWorldsAllocated = true;
- EraseGWorldBackgrounds();
- }
- catch (...)
- {
- DeleteGWorlds();
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • GWorldNeedsSynching
- // ---------------------------------------------------------------------------
-
- Boolean
- COffscreenBehavior::GWorldNeedsSynching(void)
- {
- Rect newRect;
-
- CWindowRecord * colorWindow;
-
- colorWindow = mShadowWindow.GetMacWindow();
- newRect = colorWindow->port.portRect;
- ::OffsetRect(&newRect, -newRect.left, -newRect.top);
-
- if (newRect.right != mGWorldRect.right ||
- newRect.bottom != mGWorldRect.bottom)
- {
- return true;
- }
-
- return false;
- }
-
-
- // ---------------------------------------------------------------------------
- // • EraseGWorldBackgrounds
- // ---------------------------------------------------------------------------
-
- void
- COffscreenBehavior::EraseGWorldBackgrounds(void)
- {
- if (mAllocateBacking)
- {
- StGWorldLocker locker(mBackingGWorld);
-
- ::BackColor(whiteColor);
- ::EraseRect(&mGWorldRect);
- }
-
- {
- StGWorldLocker locker(mRenderingGWorld);
-
- ::BackColor(whiteColor);
- ::EraseRect(&mGWorldRect);
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • RenderToGWorld
- // ---------------------------------------------------------------------------
-
- Boolean
- COffscreenBehavior::RenderToGWorld(
- StGWorldLocker & inBackingLocker,
- StGWorldLocker & inRenderingLocker)
- {
- // Subclasses should override. By default, we'll
- // just copy the contents of the backing offscreen.
-
- ::CopyBits( reinterpret_cast<BitMap *>(*inBackingLocker.GetPixMap()),
- reinterpret_cast<BitMap *>(*inRenderingLocker.GetPixMap()),
- &mGWorldRect,
- &mGWorldRect,
- srcCopy,
- NULL);
-
- return true;
- }
-
-
- // ---------------------------------------------------------------------------
- // • RenderToGWorld
- // ---------------------------------------------------------------------------
-
- Boolean
- COffscreenBehavior::RenderToGWorld(
- StGWorldLocker & inRenderingLocker)
- {
- #pragma unused (inRenderingLocker)
-
- // Subclasses should override.
- return true;
- }
-
-
- // ---------------------------------------------------------------------------
- // • CopyGWorldToScreen
- // ---------------------------------------------------------------------------
-
- void
- COffscreenBehavior::CopyGWorldToScreen(
- StGWorldLocker & inRenderingLocker)
- {
- CWindowRecord * colorWindow;
- colorWindow = mShadowWindow.GetMacWindow();
-
- mShadowWindow.UseWindowsPort();
-
- StColorState colorSaver;
- ::ForeColor(blackColor);
- ::BackColor(whiteColor);
-
- ::StdBits( reinterpret_cast<BitMap *>(*inRenderingLocker.GetPixMap()),
- &mGWorldRect,
- &mGWorldRect,
- srcCopy,
- NULL);
-
- MarkOffscreenUpToDate();
- }
-
-
- // ---------------------------------------------------------------------------
- // • DetachBehavior
- // ---------------------------------------------------------------------------
-
- void
- COffscreenBehavior::DetachBehavior(void)
- {
- // Unhook our QD Proc overrides
- if (mQDProcsOverridden)
- {
- // Restore the original QD Procs
- mShadowWindow.GetMacWindow()->port.grafProcs = mOrigQDProcs;
- mQDProcsOverridden = false;
- }
-
- CWindowBehavior::DetachBehavior();
- }
-
-
- // ---------------------------------------------------------------------------
- // • SetUpForQDOverride [static]
- // ---------------------------------------------------------------------------
-
- COffscreenBehavior *
- COffscreenBehavior::SetUpForQDOverride(
- CGrafPtr inCurPort)
- {
- // Start by looking up the related shadow window...
- CWindowRecord * currentWindow = reinterpret_cast<CWindowRecord *>(inCurPort);
- CShadowWindow * shadowWindow = COutOfContextApp::sOutOfContextApp->LookUpShadowWindow(currentWindow);
-
- ThrowIfNULL_(shadowWindow);
-
- COffscreenBehavior * behavior = static_cast<COffscreenBehavior *>(shadowWindow->GetBehavior());
-
- if (behavior != NULL && behavior->mGWorldsAllocated)
- {
- behavior->CopyPortParameters(reinterpret_cast<CGrafPtr>(currentWindow));
- return behavior;
- }
-
- return NULL;
- }
-
-
- // ---------------------------------------------------------------------------
- // • CopyPixPatParam
- // ---------------------------------------------------------------------------
-
- void
- COffscreenBehavior::CopyPixPatParam(
- PixPatHandle * inSrc,
- PixPatHandle * inDest)
- {
- if (*inSrc == NULL)
- {
- if (*inDest != NULL)
- {
- ::DisposePixPat(*inDest);
- *inDest = NULL;
- }
- }
- else
- {
- if (*inDest == NULL)
- *inDest = ::NewPixPat();
-
- if (*inDest != NULL)
- ::CopyPixPat(*inSrc, *inDest);
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • CopyPortParameters
- // ---------------------------------------------------------------------------
-
- void
- COffscreenBehavior::CopyPortParameters(
- CGrafPtr inCurPort)
- {
- if (mAllocateBacking)
- {
- ::SetGWorld(mBackingGWorld, NULL);
-
- // We need to copy all the important parameters from
- // the specified port to the offscreen port.
- ::SetClip(inCurPort->clipRgn);
- //::CopyRgn(inCurPort->visRgn, mBackingGWorld->visRgn);
-
- // Make sure the origin is the same
- mBackingGWorld->portRect = inCurPort->portRect;
-
- ::RGBForeColor(&inCurPort->rgbFgColor);
- ::RGBBackColor(&inCurPort->rgbBkColor);
- mBackingGWorld->pnLoc = inCurPort->pnLoc;
- mBackingGWorld->pnMode = inCurPort->pnMode;
- mBackingGWorld->pnVis = inCurPort->pnVis;
- ::TextFont(inCurPort->txFont);
- ::TextFace(inCurPort->txFace);
- ::TextMode(inCurPort->txMode);
- ::TextSize(inCurPort->txSize);
- //mBackingGWorld->spExtra = inCurPort->spExtra;
- //mBackingGWorld->fgColor = inCurPort->fgColor;
- //mBackingGWorld->bkColor = inCurPort->bkColor;
- //mBackingGWorld->colrBit = inCurPort->colrBit;
- //mBackingGWorld->patStretch = inCurPort->patStretch;
-
- // Make a copy of the grafVars handle
- if (mBackingGWorld->grafVars != NULL)
- {
- ::DisposeHandle(mBackingGWorld->grafVars);
- mBackingGWorld->grafVars = NULL;
- }
-
- mBackingGWorld->grafVars = inCurPort->grafVars;
- ::HandToHand(&mBackingGWorld->grafVars);
- ThrowIfNULL_(mBackingGWorld->grafVars);
-
- StHandleLocker locker(mBackingGWorld->grafVars);
- GrafVars * grafVars = reinterpret_cast<GrafVars *>(*mBackingGWorld->grafVars);
-
- // Now we need to copy several of the handles hanging off of grafVars
- if (grafVars->pmFgColor != NULL)
- ::HandToHand(&grafVars->pmFgColor);
-
- if (grafVars->pmBkColor != NULL)
- ::HandToHand(&grafVars->pmBkColor);
-
- CopyPixPatParam(&inCurPort->bkPixPat, &mBackingGWorld->bkPixPat);
- CopyPixPatParam(&inCurPort->pnPixPat, &mBackingGWorld->pnPixPat);
- CopyPixPatParam(&inCurPort->fillPixPat, &mBackingGWorld->fillPixPat);
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • InitOverrideQDProcs [static]
- // ---------------------------------------------------------------------------
-
- void
- COffscreenBehavior::InitOverrideQDProcs(void)
- {
- // Start with a complete copy of the original
- ::SetStdCProcs(&sOverrideQDProcs);
-
- sOverrideQDProcs.lineProc = NewQDLineProc(&COffscreenBehavior::OverrideQDLineProc);
- sOverrideQDProcs.rectProc = NewQDRectProc(&COffscreenBehavior::OverrideQDRectProc);
- sOverrideQDProcs.rgnProc = NewQDRgnProc(&COffscreenBehavior::OverrideQDRgnProc);
- sOverrideQDProcs.bitsProc = NewQDBitsProc(&COffscreenBehavior::OverrideQDBitsProc);
- sOverrideQDProcs.textProc = NewQDTextProc(&COffscreenBehavior::OverrideQDTextProc);
- // sOverrideQDProcs.txMeasProc = NewQDTxMeasProc(&COffscreenBehavior::OverrideQDTxMeasProc);
-
- sOverrideQDProcsInited = true;
- }
-
-
- #pragma mark -
- #pragma mark • Static QD Override Procs
-
- // ---------------------------------------------------------------------------
- // • OverrideQDTextProc [static]
- // ---------------------------------------------------------------------------
-
- pascal void
- COffscreenBehavior::OverrideQDTextProc(
- short inByteCount,
- Ptr inTextBuf,
- Point inNumer,
- Point inDenom)
- {
- try
- {
- StCPortSaver portSaver;
-
- COffscreenBehavior * behavior = SetUpForQDOverride(portSaver.GetSavedPort());
-
- if (behavior != NULL)
- behavior->DoQDText(portSaver.GetSavedPort(), inByteCount, inTextBuf, inNumer, inDenom);
- }
- catch (...)
- {
- // Make sure we don't throw back into QD
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • OverrideQDLineProc [static]
- // ---------------------------------------------------------------------------
-
- pascal void
- COffscreenBehavior::OverrideQDLineProc(
- Point inNewPt)
- {
- try
- {
- StCPortSaver portSaver;
-
- COffscreenBehavior * behavior = SetUpForQDOverride(portSaver.GetSavedPort());
-
- if (behavior != NULL)
- behavior->DoQDLine(portSaver.GetSavedPort(), inNewPt);
- }
- catch (...)
- {
- // Make sure we don't throw back into QD
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • OverrideQDRectProc [static]
- // ---------------------------------------------------------------------------
-
- pascal void
- COffscreenBehavior::OverrideQDRectProc(
- GrafVerb inVerb,
- Rect * inRect)
- {
- try
- {
- StCPortSaver portSaver;
-
- COffscreenBehavior * behavior = SetUpForQDOverride(portSaver.GetSavedPort());
-
- if (behavior != NULL)
- behavior->DoQDRect(portSaver.GetSavedPort(), inVerb, inRect);
- }
- catch (...)
- {
- // Make sure we don't throw back into QD
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • OverrideQDRgnProc [static]
- // ---------------------------------------------------------------------------
-
- pascal void
- COffscreenBehavior::OverrideQDRgnProc(
- GrafVerb inVerb,
- RgnHandle inRgn)
- {
- try
- {
- StCPortSaver portSaver;
-
- COffscreenBehavior * behavior = SetUpForQDOverride(portSaver.GetSavedPort());
-
- if (behavior != NULL)
- behavior->DoQDRgn(portSaver.GetSavedPort(), inVerb, inRgn);
- }
- catch (...)
- {
- // Make sure we don't throw back into QD
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • OverrideQDBitsProc [static]
- // ---------------------------------------------------------------------------
-
- pascal void
- COffscreenBehavior::OverrideQDBitsProc(
- BitMap * inSrcBits,
- Rect * inSrcRect,
- Rect * inDstRect,
- short inMode,
- RgnHandle inMaskRgn)
- {
- try
- {
- StCPortSaver portSaver;
-
- COffscreenBehavior * behavior = SetUpForQDOverride(portSaver.GetSavedPort());
-
- if (behavior != NULL)
- {
- CGrafPtr origPort;
- origPort = portSaver.GetSavedPort();
-
- // Are they copying from the screen itself?
- if (inSrcBits->baseAddr == ::LMGetScrnBase() &&
- behavior->mAllocateBacking)
- {
- behavior->DoQDBits(behavior->mBackingGWorld,
- inSrcBits, inSrcRect, inDstRect, inMode, inMaskRgn);
- }
- else
- {
- behavior->DoQDBits(portSaver.GetSavedPort(), inSrcBits,
- inSrcRect, inDstRect, inMode, inMaskRgn);
- }
- }
- }
- catch (...)
- {
- // Make sure we don't throw back into QD
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • OverrideQDTxMeasProc [static]
- // ---------------------------------------------------------------------------
-
- pascal SInt16
- COffscreenBehavior::OverrideQDTxMeasProc(
- SInt16 inByteCount,
- Ptr inTextAddr,
- Point * inNumer,
- Point * inDenom,
- FontInfo * inInfo)
- {
- SInt16 textWidth = 0;
-
- try
- {
- StCPortSaver portSaver;
-
- COffscreenBehavior * behavior = SetUpForQDOverride(portSaver.GetSavedPort());
-
- if (behavior != NULL)
- textWidth = behavior->DoQDTxMeas(portSaver.GetSavedPort(), inByteCount, inTextAddr, inNumer, inDenom, inInfo);
- }
- catch (...)
- {
- // Make sure we don't throw back into QD
- }
-
- return textWidth;
- }
-
-
- #pragma mark -
- #pragma mark • Virtual QD Procs
-
- // ---------------------------------------------------------------------------
- // • DoQDBits
- // ---------------------------------------------------------------------------
-
- void
- COffscreenBehavior::DoQDBits(
- CGrafPtr inOrigPort,
- BitMap * inSrcBits,
- Rect * inSrcRect,
- Rect * inDstRect,
- short inMode,
- RgnHandle inMaskRgn)
- {
- #pragma unused (inOrigPort)
-
- if (mAllocateBacking)
- {
- if (mFinderOffscreen == NULL)
- {
- // WARNING: This is a big, scary assumption. We are assuming that
- // the source bits is a pix map handle.
- mFinderOffscreen = reinterpret_cast<PixMapHandle>(inSrcBits);
- }
-
- StGWorldLocker locker(mBackingGWorld);
- ::StdBits(inSrcBits, inSrcRect, inDstRect, inMode, inMaskRgn);
- MarkOffscreenChanged();
-
- #if UPDATE_WHEN_TRACKING
- // If we're currently tracking, update immediately
- if (::Button())
- COutOfContextApp::sOutOfContextApp->GiveShadowWindowsTime(false);
- #endif
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • DoQDRect
- // ---------------------------------------------------------------------------
-
- void
- COffscreenBehavior::DoQDRect(
- CGrafPtr inOrigPort,
- GrafVerb inVerb,
- Rect * inRect)
- {
- #pragma unused (inOrigPort)
-
- if (mAllocateBacking)
- {
- StGWorldLocker locker(mBackingGWorld);
- ::StdRect(inVerb, inRect);
- MarkOffscreenChanged();
-
- #if UPDATE_WHEN_TRACKING
- // If we're currently tracking, update immediately
- if (::Button())
- COutOfContextApp::sOutOfContextApp->GiveShadowWindowsTime(false);
- #endif
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • DoQDRgn
- // ---------------------------------------------------------------------------
-
- void
- COffscreenBehavior::DoQDRgn(
- CGrafPtr inOrigPort,
- GrafVerb inVerb,
- RgnHandle inRgn)
- {
- #pragma unused (inOrigPort)
-
- if (mAllocateBacking)
- {
- StGWorldLocker locker(mBackingGWorld);
- ::StdRgn(inVerb, inRgn);
- MarkOffscreenChanged();
-
- #if UPDATE_WHEN_TRACKING
- // If we're currently tracking, update immediately
- if (::Button())
- COutOfContextApp::sOutOfContextApp->GiveShadowWindowsTime(false);
- #endif
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • DoQDLine
- // ---------------------------------------------------------------------------
-
- void
- COffscreenBehavior::DoQDLine(
- CGrafPtr inOrigPort,
- Point inNewPt)
- {
- if (mAllocateBacking)
- {
- StGWorldLocker locker(mBackingGWorld);
- ::StdLine(inNewPt);
-
- // Update the pen location
- inOrigPort->pnLoc = inNewPt;
- MarkOffscreenChanged();
-
- #if UPDATE_WHEN_TRACKING
- // If we're currently tracking, update immediately
- if (::Button())
- COutOfContextApp::sOutOfContextApp->GiveShadowWindowsTime(false);
- #endif
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • DoQDText
- // ---------------------------------------------------------------------------
-
- void
- COffscreenBehavior::DoQDText(
- CGrafPtr inOrigPort,
- short inByteCount,
- Ptr inTextBuf,
- Point inNumer,
- Point inDenom)
- {
- if (mAllocateBacking)
- {
- StGWorldLocker locker(mBackingGWorld);
- ::StdText(inByteCount, inTextBuf, inNumer, inDenom);
-
- // Update the pen location
- inOrigPort->pnLoc = mBackingGWorld->pnLoc;
- MarkOffscreenChanged();
-
- #if UPDATE_WHEN_TRACKING
- // If we're currently tracking, update immediately
- if (::Button())
- COutOfContextApp::sOutOfContextApp->GiveShadowWindowsTime(false);
- #endif
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • DoQDTxMeas
- // ---------------------------------------------------------------------------
-
- SInt16
- COffscreenBehavior::DoQDTxMeas(
- CGrafPtr inOrigPort,
- SInt16 inByteCount,
- Ptr inTextAddr,
- Point * inNumer,
- Point * inDenom,
- FontInfo * inInfo)
- {
- #pragma unused (inOrigPort)
-
- SInt16 textWidth = 0;
-
- if (mAllocateBacking)
- {
- StGWorldLocker locker(mBackingGWorld);
-
- // Call through to the original
- textWidth = CallQDTxMeasProc(mOrigQDProcs->txMeasProc, inByteCount, inTextAddr, inNumer, inDenom, inInfo);
- }
-
- return textWidth;
- }
-
-
-
-
-
-
-